﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using CompanyInformationObjects;

namespace XMLTest
{
	public class XmlValidator
	{
		// TODO: Fel att hantera: Fil saknas (antingen XML eller XSD); eller övriga filhanteringsfel (låsta filer osv)

		// TODO: Fel att hantera: Korrupt data i filen
		// TODO: Fel att hantera: Saknad data i filen, som inte är optional (vilken i så fall ska tolkas som NULL)
		// TODO: Fel att hantera: Identifiera kända exceptions och hantera dem vederbörligen.
		// TODO: Fel att hantera: Okända/ oväntade exceptions.


		public static bool IsValid(string XMLFile, string XSDFile)
		{
			//http://stackoverflow.com/questions/1705430/xmlserializer-validation

			var schemas = new XmlSchemaSet();
			schemas.Add(null, XSDFile);

			List<ValidationEventArgs> validationExceptionList = new List<ValidationEventArgs>();

			//let's prepare some settings
			var settings = new XmlReaderSettings	{
														Schemas = schemas,
														ValidationType = ValidationType.Schema,
														ValidationFlags = XmlSchemaValidationFlags.ProcessIdentityConstraints | XmlSchemaValidationFlags.ReportValidationWarnings
													};

			//what shall we do when we bump into an Validation error (against the XSD)?
			settings.ValidationEventHandler += delegate(object sender, ValidationEventArgs args)	{
																										if (args.Severity == XmlSeverityType.Error)
																										{
																											//add the error to a list
																											validationExceptionList.Add(args);
																										}
																									};

			using (var input = new StreamReader(XMLFile))
			{
				using (XmlReader reader = XmlReader.Create(input, settings))
				{
					XmlSerializer ser = new XmlSerializer(typeof(CompanyInformationContainer));
					try
					{
						//try to validate 
						ser.Deserialize(reader);
					}
					catch (InvalidOperationException e)
					{
						//this exception occurs for example when there are more than one identical attribute for an read XML-element:
						// f ex <Konto Kontonr="7570" Namn="Premier" NK="1" NK="2" Momsrad="0" Rekoll="1" Momskoll="1" NKkont="true" Normsaldo="2" />
						throw;
					}
				}
			}

			//do we have any errors?
			if (validationExceptionList.Count > 0)
			{
				throw new XmlValidatorException(validationExceptionList);
			}

			//everything is allright
			return true;
		}
	}

	public class XmlValidatorException : Exception
	{
		private XmlValidatorException() : base(){}

		public XmlValidatorException(List<ValidationEventArgs> validationExceptions)
			: base()
		{
			ValidationExceptions = validationExceptions;
		}

		public List<ValidationEventArgs> ValidationExceptions { get; private set; }

	}

}
